package com.gome.ss.core.plugin;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;

import com.gome.spiderkit.client.Utils;
import com.gome.ss.core.download.SpiderRequest;
import com.gome.ss.core.download.SpiderRequestInterface;
import com.gome.ss.core.download.StartRequest;
import com.gome.ss.core.queue.QueueCache;
import com.gome.ss.core.schedule.QuartzManager;
import com.gome.ss.core.schedule.ScheduJobConfig;
import com.gome.ss.core.schedule.ScheduleCore;
import com.gome.ss.core.schedule.ScheduleManager;
import com.gome.ss.core.schedule.TriggerConfig;
import com.mongodb.DBObject;

public class PluginTaskProcess extends ScheduJobConfig implements PluginProcessInterface {
	private static Logger logger = Logger.getLogger(PluginTaskProcess.class);
	
	private final String STOPBYUSER = "stop by user";
	private final String STOPNORMAL = "stop normal";
	
	private SpiderPluginHandle handle = null;
	private boolean isLaunched = false;
	
	private TriggerConfig trigger = null;
	
	private boolean incremental = false;
	
	public PluginTaskProcess(SpiderPluginHandle handle) {
		this.handle = handle;
		this.setJobName(handle.getPluginName() + "." + handle.getPluginQualified());
		this.setJobGroup(handle.getPluginName());
		this.taskID = createTaskID(handle.getPluginName(), handle.getPluginQualifiedName(), handle.getPluginQualified());
	}
	
	public void setTrigger(TriggerConfig trigger) {
		this.trigger = trigger;
		trigger.setTriggerName(handle.getPluginName() + "." + handle.getPluginQualified());
	}
	
	public TriggerConfig getTrigger() {
		return this.trigger;
	}
	
	private void removeJob() throws SchedulerException {
		try {
			QuartzManager.removeJob(this.getJobName(), this.getJobGroup(), trigger.getTriggerName(), trigger.getTrggerGroup());
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			throw e;
		}
	}
	
	@Override
	public void launch() throws Exception {
		// TODO Auto-generated method stub
		if (isLaunched)
			return;
		isLaunched = true;
		
		try {
			QuartzManager.addJob(this.getJobName(), this.getJob(), trigger.getTrigger());
			logger.info("Launch plugin : " + this.getJobName() + " | " + this.getTaskID());
		} catch (Exception e) {
			handle.setProcessing(false);
			throw e;
		}
	}

	@Override
	public void close() throws Exception {
		// TODO Auto-generated method stub
		if (!isLaunched)
			return;
		
		isLaunched = false;
		incremental = false;
		
		removeJob();
		
		if (handle.isProcessing()) {
			handle.stop();
			
			ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).addToStopTaskList(taskID);
			saveTaskDetailToHistory(STOPBYUSER);
			
			taskID = createTaskID(handle.getPluginName(), handle.getPluginQualifiedName(), handle.getPluginQualified());
		}
		
		logger.info("Close plugin : " + this.getJobName() + " | " + this.getTaskID());
	}
	
	@Override
	public void stop() throws Exception {
		// TODO Auto-generated method stub
		if (!isLaunched)
			return;
		
		if (handle.isProcessing()) {
			handle.stop();
			ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).addToStopTaskList(taskID);
			saveTaskDetailToHistory(STOPBYUSER);
			taskID = createTaskID(handle.getPluginName(), handle.getPluginQualifiedName(), handle.getPluginQualified());
			doStop();
		}
	}
	
	private void doStop() {
		
		logger.info("Stop plugin : " + this.getJobName() + " | " + this.getTaskID());
		if (trigger.isNormalType()) {
			isLaunched = false;
			try {
				removeJob();
			} catch (SchedulerException e) {
				logger.error(Utils.getTrace(e));
			}
		}
		
		if (trigger.isCycleType()) {
			incremental = true;
			
			try {
				removeJob();
			} catch (Exception e) {
				logger.error(Utils.getTrace(e));
			}
			
			try {
				QuartzManager.addJob(this.getJobName(), this.getJob(), trigger.getTrigger());
				logger.info("Cycle plugin : " + this.getJobName() + " | " + this.getTaskID());
			} catch (Exception e) {
				handle.setProcessing(false);
				logger.error(Utils.getTrace(e));
			}
		}
	}
	
	@Override
	public boolean isLaunched() {
		// TODO Auto-generated method stub
		return isLaunched;
	}
	
	@Override
	public boolean checkProcessing() {
		// TODO Auto-generated method stub
		if (!isLaunched)
			return false;
		
		updateTaskReference(handle.getPluginName(), handle.getPluginQualified(), this.taskID,
				ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).taskReference(this.taskID),
				ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).taskReferenceInThreadPool(this.taskID));
		
		if (handle.getStarted() && handle.isProcessing()) {
			if (ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).taskReference(this.taskID) <= 0) {
				handle.stop();
				saveTaskDetailToHistory(STOPNORMAL);
				taskID = createTaskID(handle.getPluginName(), handle.getPluginQualifiedName(), handle.getPluginQualified());
				doStop();
			}
		}
		
		return handle.isProcessing();
	}
	
	private void saveTaskDetailToHistory(String stopStatus) {
		int totalRef = ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).taskTotalReference(this.taskID);
		updateTaskStopStatus(handle.getPluginName(), handle.getPluginQualifiedName(), this.taskID, stopStatus, totalRef);
		ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).cleanTaskTotalReference(this.taskID);
		ScheduleManager.getInstance().getScheduleCore(handle.getPluginQualifiedName()).removeTaskInThreadPool(this.taskID);
	}
	
	public List<DBObject> getHistoryTaskInfo() {
		return getHistoryTaskInfo(handle.getPluginName(), handle.getPluginQualifiedName());
	}
	
	public  JobDetail getJob() {
		List<SpiderRequestInterface> requests = new ArrayList<SpiderRequestInterface>();
		for (StartRequest req : handle.getStartReqs()) {
			SpiderRequestInterface request = SpiderRequest.create(req.link, req.groupName, handle.getPluginName(), req.qualified, QueueCache.defaultPriority, req.retryCount);
			requests.add(request);
		}
		
		JobDataMap newJobDataMap = new JobDataMap();
		newJobDataMap.put("startMethod", handle.getStartRequestMethod());
		newJobDataMap.put("pluginTaskProcess", this);
		newJobDataMap.put("handle", handle);
		newJobDataMap.put("requests", requests);
		newJobDataMap.put("scheduJobConfig", this);
		newJobDataMap.put("incremental", incremental);
		
		return this.getJobBuilder(PluginTaskBase.class).setJobData(newJobDataMap).build();
	}
}
